package com.edu.hre.struts.action.leave;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import org.apache.struts.util.LabelValueBean;

import com.edu.hre.common.cache.PassiveDynaCache;
import com.edu.hre.common.utils.BeanFinder;
import com.edu.hre.common.utils.CommonUtils;
import com.edu.hre.common.utils.DynamicConfig;
import com.edu.hre.common.utils.RequestUtils;
import com.edu.hre.db.pojo.HreEmployee;
import com.edu.hre.db.pojo.HreLeaveRemain;
import com.edu.hre.db.pojo.HreLeaveRequest;
import com.edu.hre.db.pojo.HreLeaveType;
import com.edu.hre.db.pojo.HreUser;
import com.edu.hre.db.service.BaseService;
import com.edu.hre.db.sql.leave.LeaveRequestDAOService;
import com.edu.hre.db.utils.Compare;
import com.edu.hre.struts.action.admin.ConfigurationListAction;
import com.edu.hre.struts.form.admin.ConfigurationForm;
import com.edu.hre.struts.form.leave.LeaveRequestUpdateForm;

public class LeaveRequestUpdateAction extends DispatchAction {
	
	private static final Logger logger = Logger.getLogger(LeaveRequestUpdateAction.class);
	private static final PassiveDynaCache passiveDynaCache = BeanFinder.getBean(PassiveDynaCache.BEAN_NAME, PassiveDynaCache.class);
	private static final BaseService baseService = BeanFinder.getBean(BaseService.BEAN_NAME, BaseService.class);
	private static final LeaveRequestDAOService leaveRequestDAOService = BeanFinder.getBean(LeaveRequestDAOService.BEAN_NAME, LeaveRequestDAOService.class);
	private static final SimpleDateFormat hourFormat = new SimpleDateFormat("HH");
	private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
	private static final SimpleDateFormat dateFormatMinute = new SimpleDateFormat("MM/dd/yyyy HH:mm");
	
	public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
		CommonUtils.println(CommonUtils.getSourceCodeLocation());
		LeaveRequestUpdateForm beanForm = (LeaveRequestUpdateForm) form;
		HreUser user = (HreUser) request.getSession().getAttribute(RequestUtils.Attribute.USER_INFO);
		beanForm.setIsAddNew(true);
		beanForm.setEmpNum(user.getEmpNumber());
		
		List <LabelValueBean> listSpvs = leaveRequestDAOService.getSupervisorsOfEmp("" + user.getEmpNumber());
		beanForm.setSupervisorList(listSpvs);
		List <HreLeaveType> listLeaveType = baseService.getPojos(null, -1, null, null, null, 0, 0, HreLeaveType.class);
		hiddenLeaveType(user, listLeaveType);
		beanForm.setLeaveTypeList(listLeaveType);
		
		String startTime = DynamicConfig.getConfig(DynamicConfig.START_TIME);
		if(startTime == null){
			startTime = "8h:00";
		}
		String noonTime = "12h:00";
		String endTime = DynamicConfig.getConfig(DynamicConfig.END_TIME);
		if(endTime == null){
			endTime = "18h:00";
		}
		
		List<LabelValueBean> listFirstTime = new ArrayList<LabelValueBean>();
		listFirstTime.add(new LabelValueBean(startTime, startTime));
		listFirstTime.add(new LabelValueBean(noonTime, noonTime));
		listFirstTime.add(new LabelValueBean(endTime, endTime));
		beanForm.setListFirstTime(listFirstTime);
		if(beanForm.getFirstTimeValue() == null){
			beanForm.setFirstTimeValue(startTime);
		} 
		
		List<LabelValueBean> listLastTime = new ArrayList<LabelValueBean>();
		listLastTime.add(new LabelValueBean(startTime, startTime));
		listLastTime.add(new LabelValueBean(noonTime, noonTime));
		listLastTime.add(new LabelValueBean(endTime, endTime));
		beanForm.setListLastTime(listLastTime); 
		if(beanForm.getLastTimeValue() == null){
			beanForm.setLastTimeValue(endTime);
		} 
		
		if(request.getParameter("btnAdd") == null){ 
			beanForm.setMessage(""); 
			if(listSpvs != null && listSpvs.size() != 0){
				beanForm.setSupervisorNum(Integer.parseInt(listSpvs.get(0).getValue())); 
			}
			beanForm.setFirstLeave(new Date());
			beanForm.setLastLeave(new Date()); 
			beanForm.setLeaveTypeId(listLeaveType.get(0).getId());
			return mapping.findForward("leaveRequestUpdate");
		}
		if(beanForm.getFirstLeave() == null || beanForm.getLastLeave() == null){
			beanForm.setMessage("Please enter first and last leave date");
			return mapping.findForward("leaveRequestUpdate");
		}
		String firstLeaveString = dateFormat.format(beanForm.getFirstLeave());
		firstLeaveString += " " + beanForm.getFirstTimeValue().replace("h", "");
		beanForm.setFirstLeave(dateFormatMinute.parse(firstLeaveString));
		
		String lastLeaveString = dateFormat.format(beanForm.getLastLeave());
		lastLeaveString += " " + beanForm.getLastTimeValue().replace("h", "");
		beanForm.setLastLeave(dateFormatMinute.parse(lastLeaveString));
		
		if(beanForm.getFirstLeave().compareTo(beanForm.getLastLeave()) >= 0){
			beanForm.setMessage("First leave date must be greater than last leave date!");
			return mapping.findForward("leaveRequestUpdate");
		}
		HreLeaveRequest hreLeaveRequest = baseService.getFirstPojoAnd(
				new String[]{"empNum", "firstLeave", "lastLeave"}, 
				new int[]{Compare.EQUAL, Compare.LESS, Compare.GREATER}, 
				new Object[]{user.getEmpNumber(), beanForm.getLastLeave(), beanForm.getFirstLeave()}, null, null, 0, HreLeaveRequest.class);
		if(hreLeaveRequest != null){
			beanForm.setMessage("Entered dates are invalid interval");
			return mapping.findForward("leaveRequestUpdate");
		}
		if(beanForm.getSupervisorNum() == 0){
			beanForm.setMessage("Can not create leave request because you have no supervisor!");
			return mapping.findForward("leaveRequestUpdate");
		}
		if(beanForm.getLeaveTypeId() == 2){
			float totalLeaved = getTotalPaidLeavedDays(user.getEmpNumber()) + computeLeaveDays(beanForm.getFirstLeave(), beanForm.getLastLeave());
			float grantLeave = getTotalGrantedLeaveDays(user.getEmpNumber());
			if(totalLeaved > grantLeave){
				beanForm.setMessage("Can not create leave request with paid leave type any more!");
				return mapping.findForward("leaveRequestUpdate");
			}
		}
		HreLeaveRequest tmp = new HreLeaveRequest(user.getEmpNumber(), beanForm.getFirstLeave(), beanForm.getLastLeave(),
				beanForm.getSupervisorNum(), null,  beanForm.getLeaveTypeId(), new Date(), new Date(), beanForm.getEmpComment(), null);
		if(!baseService.saveOrUpdate(tmp)){
			beanForm.setMessage("Insert leave request is failed, please try again!");
			return mapping.findForward("leaveRequestUpdate");
		}  
		response.getWriter().write(
				 "<script language=\"javascript\">\n" +
						" parent.dw.close();" + 
						" parent.document.forms[0].submit(); \n" +
				 "</script>");
		String key = RequestUtils.Attribute.LEAVE_APPROVAL_NOTIFICATION + beanForm.getSupervisorNum();
		passiveDynaCache.removeCachedItem(key);
		return null;
	}
	
	
	public ActionForward edit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
		CommonUtils.println(CommonUtils.getSourceCodeLocation());
		LeaveRequestUpdateForm beanForm = (LeaveRequestUpdateForm) form;
		HreUser user = (HreUser) request.getSession().getAttribute(RequestUtils.Attribute.USER_INFO);
		beanForm.setIsAddNew(false);
		beanForm.setEmpNum(user.getEmpNumber());
		
		List <LabelValueBean> listSpvs = leaveRequestDAOService.getSupervisorsOfEmp("" + user.getEmpNumber());
		beanForm.setSupervisorList(listSpvs);
		List <HreLeaveType> listLeaveType = baseService.getPojos(null, -1, null, null, null, 0, 0, HreLeaveType.class);
		hiddenLeaveType(user, listLeaveType);
		beanForm.setLeaveTypeList(listLeaveType);
	
		String startTime = DynamicConfig.getConfig(DynamicConfig.START_TIME);
		String noonTime = "12h:00";
		String endTime = DynamicConfig.getConfig(DynamicConfig.END_TIME);
		
		List<LabelValueBean> listFirstTime = new ArrayList<LabelValueBean>();
		listFirstTime.add(new LabelValueBean(startTime, startTime));
		listFirstTime.add(new LabelValueBean(noonTime, noonTime));
		listFirstTime.add(new LabelValueBean(endTime, endTime));
		beanForm.setListFirstTime(listFirstTime); 
		
		List<LabelValueBean> listLastTime = new ArrayList<LabelValueBean>();
		listLastTime.add(new LabelValueBean(startTime, startTime));
		listLastTime.add(new LabelValueBean(noonTime, noonTime));
		listLastTime.add(new LabelValueBean(endTime, endTime));
		beanForm.setListLastTime(listLastTime);  
		
		int id = Integer.parseInt(request.getParameter("id"));
		HreLeaveRequest tmp = baseService.getPojo(id, HreLeaveRequest.class);
		
		if(request.getParameter("btnEdit") == null){ 
			beanForm.setMessage("");   
			beanForm.setId(id);
			beanForm.setFirstLeave(tmp.getFirstLeave());
			beanForm.setLastLeave(tmp.getLastLeave()); 
			beanForm.setLeaveTypeId(tmp.getLeaveTypeId());
			beanForm.setSupervisorNum(tmp.getSupervisorNum());
			beanForm.setEmpComment(tmp.getEmpComment());
			String firstLeaveString = dateFormatMinute.format(tmp.getFirstLeave());
			String lastLeaveString = dateFormatMinute.format(tmp.getLastLeave());
			beanForm.setFirstTimeValue(firstLeaveString.split(" ")[1].replace(":", "h:"));
			beanForm.setLastTimeValue(lastLeaveString.split(" ")[1].replace(":", "h:"));
			return mapping.findForward("leaveRequestUpdate");
		}
		if(tmp.getApproved() != null){
			beanForm.setMessage("Can not edit this request because your supervisor have been response it!");
			return mapping.findForward("leaveRequestUpdate");
		}
		if(beanForm.getFirstLeave() == null || beanForm.getLastLeave() == null){
			beanForm.setMessage("Please enter first and last leave date");
			return mapping.findForward("leaveRequestUpdate");
		}
		String firstLeaveString = dateFormat.format(beanForm.getFirstLeave());
		firstLeaveString += " " + beanForm.getFirstTimeValue().replace("h", "");
		beanForm.setFirstLeave(dateFormatMinute.parse(firstLeaveString));
		
		String lastLeaveString = dateFormat.format(beanForm.getLastLeave());
		lastLeaveString += " " + beanForm.getLastTimeValue().replace("h", "");
		beanForm.setLastLeave(dateFormatMinute.parse(lastLeaveString));
		
		if(beanForm.getFirstLeave().compareTo(beanForm.getLastLeave()) >= 0){
			beanForm.setMessage("First leave date must be greater than last leave date!");
			return mapping.findForward("leaveRequestUpdate");
		}
		List <HreLeaveRequest> listLeaveRequest = baseService.getPojosAnd(
				new String[]{"empNum", "firstLeave", "lastLeave", "id"}, 
				new int[]{Compare.EQUAL, Compare.LESS, Compare.GREATER, Compare.NOT_EQUAL}, 
				new Object[]{user.getEmpNumber(), beanForm.getLastLeave(), beanForm.getFirstLeave(), id}, null, null,0 , 0, HreLeaveRequest.class);
		if(listLeaveRequest != null && listLeaveRequest.size() > 0){
			beanForm.setMessage("Entered dates are invalid interval");
			return mapping.findForward("leaveRequestUpdate");
		}
		if(beanForm.getSupervisorNum() == 0){
			beanForm.setMessage("Can not create leave request because you have no supervisor!");
			return mapping.findForward("leaveRequestUpdate");
		}
		if(beanForm.getLeaveTypeId() == 2){
			float totalLeaved = getTotalPaidLeavedDays(user.getEmpNumber()) + computeLeaveDays(beanForm.getFirstLeave(), beanForm.getLastLeave());
			if(tmp.getLeaveTypeId() == 2){
				totalLeaved -= tmp.getTotalLeaved() == null ? computeLeaveDays(tmp.getFirstLeave(), tmp.getLastLeave()) : tmp.getTotalLeaved();
			}
			float grantLeave = getTotalGrantedLeaveDays(user.getEmpNumber());
			if(totalLeaved > grantLeave){
				beanForm.setMessage("Can not create leave request with paid leave type any more!");
				return mapping.findForward("leaveRequestUpdate");
			}
		}
		tmp.setFirstLeave(beanForm.getFirstLeave());
		tmp.setLastLeave(beanForm.getLastLeave());
		tmp.setSupervisorNum(beanForm.getSupervisorNum());
		tmp.setLeaveTypeId(beanForm.getLeaveTypeId());
		tmp.setEmpComment(beanForm.getEmpComment());
		if(!baseService.saveOrUpdate(tmp)){
			beanForm.setMessage("Update leave request is failed, please try again!");
			return mapping.findForward("leaveRequestUpdate");
		}
		response.getWriter().write(
				 "<script language=\"javascript\">\n" +
						" parent.dw.close();" + 
						" parent.document.forms[0].submit(); \n" +
				 "</script>");
		String key = RequestUtils.Attribute.LEAVE_APPROVAL_NOTIFICATION + beanForm.getSupervisorNum();
		passiveDynaCache.removeCachedItem(key);
		return null;
	}
	
	
	private void hiddenLeaveType(HreUser user, List <HreLeaveType> listLeaveType){
		if(isLeavedMax(user.getEmpNumber())){
			for(int i = 0; listLeaveType != null && i < listLeaveType.size(); i++){
				if(listLeaveType.get(i).getId() == 2){
					listLeaveType.remove(i);
					break;
				}
			}
		}
	}
	
	public static boolean isLeavedMax(int empNum){
		float grantedLeaveDays = getTotalGrantedLeaveDays(empNum);
		float totalLeaved = getTotalPaidLeavedDays(empNum);
		CommonUtils.println("grantedLeaveDays: " + grantedLeaveDays + ", totalLeaved: " + totalLeaved);
		return (totalLeaved >= grantedLeaveDays);
	} 
	
	public static float computeLeaveDays(Date start, Date end) throws ParseException{
		Date d1 = dateFormat.parse(dateFormat.format(start));
		Date d2 = dateFormat.parse(dateFormat.format(end));
		float diff = (float) ((d2.getTime() - d1.getTime()) / (1000.0 * 60 * 60 * 24));
		int hourD1 = Integer.parseInt(hourFormat.format(start));
		if(hourD1 == 12){
			diff -= 0.5;
		} else if(hourD1 > 12){
			diff -= 1;
		}
		int hourD2 = Integer.parseInt(hourFormat.format(end));
		if(hourD2 == 12){
			diff += 0.5;
		} else if(hourD2 > 12){
			diff += 1;
		}
		return diff;
	}
	
	public static float getTotalGrantedLeaveDays(int empNum){
		HreLeaveRemain leaveRemain = baseService.getFirstPojoAnd(new String[]{"empNum", "yearNumber"}, new int[]{Compare.EQUAL, Compare.EQUAL}, new Object[]{empNum, new Date().getYear() + 1900}, null, null, 0, HreLeaveRemain.class);
		if(leaveRemain != null){
			return leaveRemain.getRemainDay();
		}
		float maxLeaveDays = CommonUtils.parseFloat(DynamicConfig.getConfig(DynamicConfig.MAX_LEAVE_DAYS), 12.0f);
		float leaveDays = maxLeaveDays;
		HreEmployee me = baseService.getPojo(empNum, HreEmployee.class);
		if(me != null){
			if(me.getDateCreated().getYear() < new Date().getYear()){
				leaveDays = maxLeaveDays;
			} else {
				Calendar cal = Calendar.getInstance();
				cal.setTime(me.getDateCreated());
				float tmpFloat = (float) ((365 - cal.get(Calendar.DAY_OF_YEAR)) * (maxLeaveDays/365.0));
				tmpFloat *= 2;
				tmpFloat = Math.round(tmpFloat);
				leaveDays = tmpFloat/2;
			}
		}
		leaveRemain = new HreLeaveRemain(new Date().getYear() + 1900, leaveDays, empNum, true, null, null, new Date(), new Date());
		baseService.saveOrUpdate(leaveRemain);
		return leaveDays;
	}
	
	public static float getTotalOtherLeavedDays(int empNum){
		try {
			float totalLeavedDays = 0;
			Date year1 = dateFormat.parse("01/01/" + (new Date().getYear() + 1900));
			Date year2 = dateFormat.parse("01/01/" + (new Date().getYear() + 1900 + 1));
			List <HreLeaveRequest> listRequest = baseService.getPojosAnd(
					new String[]{"empNum", "leaveTypeId", "firstLeave", "firstLeave"}, 
					new int[]{Compare.EQUAL, Compare.NOT_EQUAL, Compare.GREATER_EQUAL, Compare.LESS}, 
					new Object[]{empNum, 2, year1, year2}, null, null, 0, 0, HreLeaveRequest.class);
			for(int i = 0; listRequest != null && i < listRequest.size(); i++){
				try {
					HreLeaveRequest tmp = listRequest.get(i);
					Float diffDay = tmp.getTotalLeaved();
					if(diffDay == null){
						diffDay = computeLeaveDays(tmp.getFirstLeave(), tmp.getLastLeave());
					}
					totalLeavedDays += diffDay;
				} catch (Exception e) {
					CommonUtils.println(e.getMessage());
				}
			}
			return totalLeavedDays;
		} catch (Exception e) {
			CommonUtils.println(e.getMessage());
			return 0;
		}
	}
	
	public static float getTotalPaidLeavedDays(int empNum){
		try {
			float totalLeavedDays = 0;
			Date year1 = dateFormat.parse("01/01/" + (new Date().getYear() + 1900));
			Date year2 = dateFormat.parse("01/01/" + (new Date().getYear() + 1900 + 1));
			List <HreLeaveRequest> listRequest = baseService.getPojosAnd(
					new String[]{"empNum", "leaveTypeId", "firstLeave", "firstLeave"}, 
					new int[]{Compare.EQUAL, Compare.EQUAL, Compare.GREATER_EQUAL, Compare.LESS}, 
					new Object[]{empNum, 2, year1, year2}, null, null, 0, 0, HreLeaveRequest.class);
			for(int i = 0; listRequest != null && i < listRequest.size(); i++){
				try {
					HreLeaveRequest tmp = listRequest.get(i);
					Float diffDay = tmp.getTotalLeaved();
					if(diffDay == null){
						diffDay = computeLeaveDays(tmp.getFirstLeave(), tmp.getLastLeave());
					}
					totalLeavedDays += diffDay;
				} catch (Exception e) {
					CommonUtils.println(e.getMessage());
				}
			}
			return totalLeavedDays;
		} catch (Exception e) {
			CommonUtils.println(e.getMessage());
			return 0;
		}
	}
}
